package com.zh.business.config.aop;

import com.zh.zhbootcommon.common.BasicConstants;
import com.zh.zhbootcommon.common.RedisKey;
import com.zh.zhbootcommon.common.result.impl.ResultCode;
import com.zh.zhbootcommon.config.exception.ZhBootException;
import com.zh.zhbootcommon.config.redis.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述: 切面设置分布式锁
 *
 * @author: yanglin
 * @Date: 2021-09-03-10:34
 * @Version: 1.0
 */
@Slf4j
@Aspect
@Order(value = 1)
@Component
public class DistributedLockAop {

    @Autowired
    RedisLock redisLock;

    private ThreadLocal<Map> redisKey = new ThreadLocal<>();

    /**
     * 按注解进行拦截
     */
    @Pointcut("@annotation(com.zh.zhbootcommon.config.annotation.DistributedLock)")
    public void distributedLock() {
    }

    /**
     * 方法执行前
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("distributedLock()")
    public void before(JoinPoint joinPoint) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        Map<String, String> map = new HashMap<>();
        // key 请求URL IP
        String url = request.getRequestURL().toString();
        String ip = request.getRemoteAddr();
        String lockKey = RedisKey.MP_ORDER_OPERATION.getValue() + url + ":" +ip;
        long time = System.currentTimeMillis() + 5000;
        boolean lock = redisLock.lock(lockKey, String.valueOf(time), BasicConstants.REDIS_LOCK_EXPER);
        if (lock) {
            map.put("key", lockKey);
            map.put("value", String.valueOf(time));
            redisKey.set(map);
            log.info("分布式锁加载成功;key->{}, value->{}", lockKey, time);
        } else {
            // log.info("分布式锁已被占用;key->{}", lockKey);
            throw new ZhBootException(ResultCode.REDIS_LOCL_FAIL.getMsg());
        }
    }

    /**
     * 环绕执行
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("distributedLock()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object result = pjp.proceed();
        return result;
    }

    /**
     * 方法执行后
     *
     * @param point
     */
    @After("distributedLock()")
    public void after(JoinPoint point) {
        Map<String, String> map = redisKey.get();
        String key = map.get("key");
        String value = map.get("value");
        try{
            // 释放锁
            redisLock.release(key, value);
            log.info("释放分布式锁;key->{}, value->{}", key, value);
        }catch (Exception e){
            throw new ZhBootException(e.getMessage());
        }

    }

}
